package tzy.recyclerview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

/**
 * Created by Administrator on 2018/1/9.
 */

public class HeaderFooterRecyclerView extends RecyclerView2 {
    private ExpandAdapter mAdapter;
    public static final int MODE_HEADER = 1 << 30;
    public static final int MODE_FOOTER = 2 << 30;
    private static final int MODE_MASK = 0x3 << 30;

    public void setOnHeaderFooterBindListener(OnHeaderFooterBindListener onHeaderFooterBindListener) {
        this.mOnHeaderFooterBindListener = onHeaderFooterBindListener;
        if (mAdapter != null) {
            mAdapter.setOnHeaderFooterBindListener(mOnHeaderFooterBindListener);
        }
    }

    private OnHeaderFooterBindListener mOnHeaderFooterBindListener;

    public interface OnHeaderFooterBindListener {
        void onBindViewHolder(ViewHolder holder, int flag, View itemView);

        ViewHolder onCreateViewHolder(ViewGroup parent, int flag);
    }

    public HeaderFooterRecyclerView(Context context) {
        this(context, null);
    }

    public HeaderFooterRecyclerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HeaderFooterRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        MySpanSizeLookup lookup = new MySpanSizeLookup();
        GridLayoutManager layoutManager = new GridLayoutManager(context, 1);
        layoutManager.setSpanSizeLookup(lookup);
        super.setLayoutManager(layoutManager);
    }

    public static int makeHeaderFooterFlag(int mode, int index) {
        return mode | index;
    }

    public static int getHeaderFooterIndex(int flag) {
        return flag &= ~MODE_MASK;
    }

    public static int getHeaderFooterMode(int flag) {
        return flag & MODE_MASK;
    }

    @Deprecated
    public void addHeaderFooterView(int flag, View view) {
        int index = getHeaderFooterIndex(flag);
        if (index < 0)
            return;
        final int mode = getHeaderFooterMode(flag);
        switch (mode) {
            case MODE_HEADER:
                addHeaderView(index, view);
                break;
            case MODE_FOOTER:
                addFooterView(index, view);
                break;
        }


    }

    @Deprecated
    public boolean removeHeaderFooterView(int flag) {
        int index = getHeaderFooterIndex(flag);
        if (index < 0)
            return false;
        final int mode = getHeaderFooterMode(flag);
        switch (mode) {
            case MODE_HEADER:
                return removeHeaderView(index);
            case MODE_FOOTER:
                return removeFooterView(index);
        }
        return false;

    }

    public boolean addHeaderFooterViewByBind(int flag) {
        int index = getHeaderFooterIndex(flag);
        if (index < 0)
            return false;
        final int mode = getHeaderFooterMode(flag);
        switch (mode) {
            case MODE_HEADER:
                return addHeaderViewByBind(index);
            case MODE_FOOTER:
                return addFooterByBind(index);
        }

        return false;

    }

    public boolean removeHeaderFooterViewByBind(int flag) {
        int index = getHeaderFooterIndex(flag);
        if (index < 0)
            return false;
        final int mode = getHeaderFooterMode(flag);
        switch (mode) {
            case MODE_HEADER:
                return removeHeaderView(index);
            case MODE_FOOTER:
                return removeFooterView(index);
        }
        return false;

    }

    public void scrollToHeaderFooter(int flag) {
        int index = getHeaderFooterIndex(flag);
        if (index < 0)
            return;
        final int mode = getHeaderFooterMode(flag);
        switch (mode) {
            case MODE_HEADER:
                scrollToHeader(index);
                break;
            case MODE_FOOTER:
                scrollToFooter(index);
                break;

        }
    }

    void scrollToHeader(int index) {
        if (mAdapter != null) {
            final int position = mAdapter.getHeaderPositionByIndex(index);
            scrollToPositionViewTop(position);
        }
    }

    void scrollToFooter(int index) {
        if (mAdapter != null) {
            final int position = mAdapter.getFooterPositionByIndex(index);
            scrollToPositionViewTop(position);
        }
    }

    void scrollToPositionViewTop(int p) {
        final GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
        layoutManager.scrollToPositionWithOffset(p,0);
    }


    @Override
    public void setLayoutManager(RecyclerView.LayoutManager layout) {
//        super.setLayoutManager(layout);
        throw new UnsupportedOperationException();
    }

//    private class ItemDecorationWrapper extends ItemDecoration {
//        private ItemDecoration mInternalItemDecoration;
//
//        public ItemDecorationWrapper(ItemDecoration decoration) {
//            this.mInternalItemDecoration = decoration;
//        }
//
//        public ItemDecorationWrapper() {
//            super();
//        }
//
//        @Override
//        public void onDraw(Canvas c, RecyclerView parent, State state) {
////            super.onDraw(c, parent, state);
//            mInternalItemDecoration.onDraw(c, parent, state);
//        }
//
//        @Override
//        public void onDraw(Canvas c, RecyclerView parent) {
//            mInternalItemDecoration.onDraw(c, parent);
//        }
//
//        @Override
//        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
//            mInternalItemDecoration.onDraw(c, parent, state);
//        }
//
//        @Override
//        public void onDrawOver(Canvas c, RecyclerView parent) {
//            mInternalItemDecoration.onDraw(c, parent);
//        }
//
//        @Override
//        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
//            final int newP = getAdapterPosition(itemPosition);
//            if (newP >= 0) {
//                mInternalItemDecoration.getItemOffsets(outRect, newP, parent);
//            }
//        }
//
//        @Override
//        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
//            final int p = ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
//            final int newP = getAdapterPosition(p);
//
//            if (newP >= 0) {
//                mInternalItemDecoration.getItemOffsets(outRect, view, parent, state);
//            }
//        }
//    }

//    @Override
//    public void addItemDecoration(ItemDecoration decor, int index) {
//        super.addItemDecoration(new ItemDecorationWrapper(decor), index);
//    }


    @Override
    public void setAdapter(RecyclerView.Adapter adapter) {
//        super.setAdapter(adapter);
        if (adapter instanceof Adapter) {
            setAdapter((Adapter) adapter);
        } else {
            throw new UnsupportedOperationException();
        }
    }

    public void setAdapter(Adapter adapter) {
        final HeaderAdapter old = mAdapter;
        setAdapterInternal(adapter, old);
    }


    public int getAdapterPosition(int positionInParent) {
        return mAdapter == null ? -1 : mAdapter.getAdapterPosition(positionInParent);
    }


//    @Override
//    public Adapter getAdapter() {
//        return mAdapter == null ? null : mAdapter.mInternalAdapter;
//    }


    @Deprecated
    public void addHeaderView(int index, View headerView) {
        if (mAdapter == null) {
//            mAdapter = new HeaderAdapter(null);
            setAdapterInternal(null, null);
        }
        mAdapter.addHeaderView(index, headerView);
    }

    public boolean addHeaderViewByBind(int index) {
        if (mAdapter == null) {
//            mAdapter = new HeaderAdapter(null);
            setAdapterInternal(null, null);
        }
        return mAdapter.addHeaderByBind(index);
    }


    public boolean removeHeaderView(int index) {
        if (mAdapter != null) {
            return mAdapter.removeHeaderView(index);
        }
        return false;
    }

    public boolean removeHeaderView(View headerView) {
        if (mAdapter != null) {
            return mAdapter.removeHeaderView(headerView);
        }
        return false;
    }

    @Deprecated
    public void addFooterView(int index, View footerView) {
        if (mAdapter == null) {
//            mAdapter = new HeaderAdapter(null);
            setAdapterInternal(null, null);
        }
        mAdapter.addFooterView(index, footerView);
    }

    public boolean addFooterByBind(int index) {
        if (mAdapter == null) {
//            mAdapter = new HeaderAdapter(null);
            setAdapterInternal(null, null);
        }
        return mAdapter.addFooterByBind(index);
    }

    public boolean removeFooterView(int index) {
        if (mAdapter != null) {
            return mAdapter.removeFooterView(index);
        }
        return false;
    }

    public boolean removeFooterView(View footerView) {
        if (mAdapter != null) {
            return mAdapter.removeFooterView(footerView);
        }
        return false;
    }

    public boolean expandLayout(boolean expand) {
        if (mAdapter != null) {
            return mAdapter.expand(expand);
        }
        return false;
    }

    public boolean isExpanded() {
        return mAdapter == null ? false : mAdapter.isExpanded();
    }


//    public HeaderAdapter getHeaderAdapter() {
//        return mAdapter;
//    }

//    public int getRealIndex(int index) {
//        return index - mAdapter.getHeaderCount();
//    }

    public int getHeaderCount() {
        return mAdapter == null ? 0 : mAdapter.getHeaderCount();
    }

    public int getFooterCount() {
        return mAdapter == null ? 0 : mAdapter.getFooterCount();
    }

    /**
     * 根据positionInParent计算是第几个HeaderView
     */
    public int getHeaderPositionWithParentPosition(int positionInParent) {
        return mAdapter == null ? -1 : mAdapter.getHeaderPositionWithParentPosition(positionInParent);
    }

    /**
     * 根据positionInParent计算是第几个FooterView
     */
    public int getFooterPositionWithParentPosition(int positionInParent) {
        return mAdapter == null ? -1 : mAdapter.getFooterPositionWithParentPosition(positionInParent);
    }

    /**
     * 根据positionInParent计算HeaderView的索引值
     */
    public int getHeaderIndexWithParentPosition(int positionInParent) {

        return mAdapter == null ? -1 : mAdapter.getHeaderIndexWithParentPosition(positionInParent);
    }

    /**
     * 根据positionInParent计算FooterView的索引值
     */
    public int getFooterIndexWithParentPosition(int positionInParent) {
        return mAdapter == null ? -1 : mAdapter.getFooterIndexWithParentPosition(positionInParent);

    }


    private void setAdapterInternal(final Adapter internalAdapter, final HeaderAdapter oldHeaderAdapter) {
        if (oldHeaderAdapter != null) {
            mAdapter = new ExpandAdapter(internalAdapter, oldHeaderAdapter);
            mAdapter.setOnHeaderFooterBindListener(mOnHeaderFooterBindListener);
        } else {
            mAdapter = new ExpandAdapter(internalAdapter);
            mAdapter.setOnHeaderFooterBindListener(mOnHeaderFooterBindListener);
        }
        resetGird();
        super.setAdapter(mAdapter);
    }

    private void resetGird() {
        GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
        layoutManager.setSpanCount(mAdapter.getTotalSpanSize());


//        GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), mAdapter.getTotalSpanSize());
//        gridLayoutManager.setSpanSizeLookup(mLookup);
    }

    private class MySpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
        @Override
        public int getSpanSize(int position) {
            return mAdapter.getSpanSize(position);
        }
    }


    @Override
    public boolean performItemClick(View child, int position, long id) {


        final int p = getAdapterPosition(position);
        if (p < 0)
            return false;

        return super.performItemClick(child, p, mAdapter.getItemId(position));

    }

//    int getAdapterItemPosition(int position) {
//        final int pos;
//        if (mAdapter == null) {
//            pos = position;
//        } else {
//            pos = mAdapter.getPositionWithExpanded(position - mAdapter.getHeaderCount());
//
//        }
//        return pos;
//
//
//    }


    static class ExpandAdapter extends HeaderAdapter {
        private boolean mExpanded;


        ExpandAdapter(Adapter adapter) {
            super(adapter);
        }

        ExpandAdapter(Adapter adapter, HeaderAdapter copyFrom) {
            super(adapter, copyFrom);
        }

        boolean expand(boolean expand) {
            if (expand != mExpanded) {
                mExpanded = expand;
                ensureInternalAdapterParams();
                if (mExpanded) {
                    notifyItemRangeInserted(getExpandStart(), getSafeExpandCount());
                } else {
                    notifyItemRangeRemoved(getExpandStart(), getSafeExpandCount());
                }
                return true;
            }
            return false;
        }

        @Override
        void ensureInternalAdapterParams() {
            super.ensureInternalAdapterParams();
            if (!mExpanded) {
                final int expandCount = getSafeExpandCount();
                mMyItemCount -= expandCount;
            }


        }

        @Override
        public int getExpandStart() {
            return getHeaderCount() + mInternalAdapter.getExpandStart();
        }

        @Override
        public int getExpandCount() {
            return mInternalAdapter.getExpandCount();
        }


        //        @Override
//        int getItemCount2() {
//            final int itemCount = super.getItemCount2();
//            if (mExpanded) {
//                return itemCount;
//            }
//            final int expandCount = getSafeExpandCount();
//            return itemCount - expandCount;
//        }

        @Override
        int getAdapterPosition(int positionInParent) {
            final int adapterPos = super.getAdapterPosition(positionInParent);
            if (adapterPos >= 0) {
                return getPositionWithExpanded(adapterPos);
            }
            return adapterPos;
        }

        private int getPositionWithExpanded(int position) {
            if (mExpanded)
                return position;

            final int expandStart = getSafeExpandStartPosition();
            int expandCount;
            if (position < expandStart) {
                expandCount = 0;
            } else {
                expandCount = getSafeExpandCount();
            }
            return position + expandCount;
        }


        private int getSafeExpandStartPosition() {
            final int startPos;
            final int itemCount;
            if (mInternalAdapter == null) {
                startPos = 0;
                itemCount = 0;
            } else {
                startPos = mInternalAdapter.getExpandStart();
                itemCount = mInternalAdapter.getItemCount();
            }

            if (startPos < 0) {
                return 0;
            }
            if (startPos > itemCount)
                return itemCount;

            return startPos;
        }

        private int getSafeExpandEndPosition() {
            final int endPos;
            final int itemCount;

            if (mInternalAdapter == null) {
                endPos = 0;
                itemCount = 0;
            } else {
                endPos = mInternalAdapter.getExpandStart() + mInternalAdapter.getExpandCount();
                itemCount = mInternalAdapter.getItemCount();
            }

            if (endPos > itemCount)
                return itemCount;
            if (endPos < 0) {
                return 0;
            }

            return endPos;
        }

        private int getSafeExpandCount() {
            final int start = getSafeExpandStartPosition();
            final int end = getSafeExpandEndPosition();
            return end - start;
        }

        boolean isExpanded() {
            return mExpanded;
        }
    }

    private static class HeaderAdapter extends Adapter<RecyclerView.ViewHolder> {
        Adapter mInternalAdapter;
        //        private ArrayList<View> headerView;
//        private ArrayList<View> footerView;
        private final SparseArray<View> mHeader;
        private final SparseArray<View> mFooter;
        private InternalAdapterDataObserver mInternalAdapterDataObserver;
        private static final int DEFAULT_MAX_EXTRA_COUNT = 2;
        int mMyItemCount;

        OnHeaderFooterBindListener mListener;

        void setOnHeaderFooterBindListener(OnHeaderFooterBindListener listener) {
            mListener = listener;
        }

        boolean addHeaderByBind(int index) {
            if (mListener == null) {
                throw new NullPointerException("setOnHeaderFooterBindListener first");
            }
            return addHeaderView(index, null);

        }

        boolean addFooterByBind(int index) {
            if (mListener == null) {
                throw new NullPointerException("setOnHeaderFooterBindListener first");
            }
            return addFooterView(index, null);
        }


        boolean addHeaderView(int index, View view) {
            if (index < 0) {
                return false;
//                throw new IllegalArgumentException("headerView index should>=0");
            }
            final int viewType = generateHeaderViewType(index);
            int positionInAdapter = getHeaderPositionByViewType(viewType);
            if (positionInAdapter > -1) {
                notifyDataSetChanged();

            } else {
                mHeader.append(viewType, view);
                positionInAdapter = getHeaderPositionByViewType(viewType);
                notifyItemInserted(positionInAdapter);
            }
            return true;

//            notifyDataSetChanged();
        }

        boolean removeHeaderView(int index) {
            final int viewType = generateHeaderViewType(index);
            int indexInArray = mHeader.indexOfKey(viewType);
            if (indexInArray > -1) {
                int indexInAdapter = mHeader.size() - indexInArray - 1;
                mHeader.removeAt(indexInArray);
                notifyItemRemoved(indexInAdapter);
                return true;
            }
            return false;
        }

        boolean removeHeaderView(View view) {
            int viewType = mHeader.indexOfValue(view);
            if (viewType > -1) {
                int indexInAdapter = mHeader.size() - viewType - 1;
                mHeader.removeAt(viewType);
                notifyItemRemoved(indexInAdapter);
                return true;
            }
            return false;
        }

        private int generateHeaderViewType(int index) {
            return -index - 1;
        }

        private int generateFooterViewType(int index) {
//            final int footerUpHeaderCount = getHeaderCount() + getInternalAdapterItemCount();
//            final int contentDownFooterX = index - footerUpHeaderCount;
            return Integer.MIN_VALUE + index;
        }

        private int generateHeaderIndexWithViewType(int viewType) {
            return -viewType - 1;
        }

        private int generateFooterIndexWithViewType(int viewType) {
            return viewType - Integer.MIN_VALUE;
        }


        boolean addFooterView(int index, View view) {
            if (index < 0) {
                return false;
//                throw new IllegalArgumentException("footerView index should>=0");
            }
            final int viewType = generateFooterViewType(index);
            int positionInAdapter = getFooterPositionByViewType(viewType);
            if (positionInAdapter > -1) {
                notifyDataSetChanged();

            } else {
                mFooter.append(viewType, view);
                positionInAdapter = getFooterPositionByViewType(viewType);
                notifyItemInserted(positionInAdapter);
            }
            return true;
        }

        int getHeaderPositionByIndex(int index) {
            final int viewType = generateHeaderViewType(index);
            return getHeaderPositionByViewType(viewType);

        }

        int getHeaderPositionByViewType(int viewType) {
            int indexInArray = mHeader.indexOfKey(viewType);
            if (indexInArray >= 0) {
//                int indexInAdapter = mHeader.size() - indexInArray - 1;
//                notifyItemChanged(indexInAdapter, null);//                mHeader.setValueAt(indexInArray, view);
                return mHeader.size() - indexInArray - 1;

            }
            return -1;
        }

        int getFooterPositionByIndex(int index) {
            final int viewType = generateFooterViewType(index);
            return getFooterPositionByViewType(viewType);
        }

        int getFooterPositionByViewType(int viewType) {
            int indexInArray = mFooter.indexOfKey(viewType);
            if (indexInArray >= 0) {
                return getHeaderCount() + mMyItemCount + indexInArray;
            }
            return -1;
        }

        boolean removeFooterView(int index) {
            final int viewType = generateFooterViewType(index);
            int indexInArray = mFooter.indexOfKey(viewType);
            if (indexInArray > -1) {
                int indexInAdapter = getHeaderCount() + mMyItemCount + indexInArray;
                mFooter.removeAt(indexInArray);
                notifyItemRemoved(indexInAdapter);
                return true;
            }
            return false;
        }

        boolean removeFooterView(View view) {
            int viewType = mFooter.indexOfValue(view);
            if (viewType > -1) {
                int indexInAdapter = getHeaderCount() + mMyItemCount + viewType;
                mFooter.removeAt(viewType);
                notifyItemRemoved(indexInAdapter);
                return true;
            }
            return false;
        }

        void ensureInternalAdapterParams() {
            if (mInternalAdapter == null) {
                mMyItemCount = 0;

            } else {
                mMyItemCount = mInternalAdapter.getItemCount();

            }
//            mInternalAdapterItemCount = mInternalAdapter == null ? 0 : mInternalAdapter.getItemCount();
        }


        HeaderAdapter(Adapter adapter, HeaderAdapter copyFrom) {
            mInternalAdapter = adapter;
            mHeader = copyFrom.mHeader;
            mFooter = copyFrom.mFooter;
            ensureInternalAdapterParams();
        }


        private HeaderAdapter(Adapter adapter) {
            mInternalAdapter = adapter;
            mHeader = new SparseArray<>(DEFAULT_MAX_EXTRA_COUNT);
            mFooter = new SparseArray<>(DEFAULT_MAX_EXTRA_COUNT);
            ensureInternalAdapterParams();
        }


//        final  int getItemCount2() {
//            return mInternalAdapterItemCount;
//        }

        @Override
        public final int getSpanSize(int position) {
            final int adapterPos = getAdapterPosition(position);
            if (adapterPos >= 0) {
                return mInternalAdapter.getSpanSize(adapterPos);
            }
            return getTotalSpanSize();
        }

        @Override
        public int getTotalSpanSize() {
            return mInternalAdapter == null ? 1 : mInternalAdapter.getTotalSpanSize();
        }

        @Override
        public final int getItemViewType(int position) {
            final int adapterPos = getAdapterPosition(position);

            if (adapterPos >= 0) {
                final int adapterType = mInternalAdapter.getItemViewType(adapterPos);
                if (adapterType < 0)
                    throw new IllegalStateException("adapter viewType should >=0");
                return adapterType;
            } else {
                final int headerType = findHeaderViewTypeByPositionInParent(position);
                if (headerType < 0)
                    return headerType;

                final int footerType = findFooterViewTypeByPositionInParent(position);
                if (footerType < 0)
                    return footerType;

                throw new IllegalStateException("---------------------------");

            }


        }

        private int findHeaderViewTypeByPositionInParent(int positionInParent) {
            int contentUpHeaderX = positionInParent - getHeaderCount();
            if (contentUpHeaderX < 0) {
                return mHeader.keyAt(mHeader.size() - 1 - positionInParent);
            }
            return 0;

        }

        private int findFooterViewTypeByPositionInParent(int positionInParent) {
            final int footerUpHeaderCount = getHeaderCount() + mMyItemCount;
            final int contentDownFooterX = positionInParent - footerUpHeaderCount;
            if (contentDownFooterX >= 0) {
                return mFooter.keyAt(contentDownFooterX);
            }
            return 0;
        }

        @Override
        public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

            if (viewType < 0) {

                View v = null;

                int headIndex;
                int footIndex;

                if ((headIndex = mHeader.indexOfKey(viewType)) >= 0) {
                    if (mListener != null) {
                        return mListener.onCreateViewHolder(parent, makeHeaderFooterFlag(MODE_HEADER, generateHeaderIndexWithViewType(viewType)));
                    } else {
                        v = mHeader.valueAt(headIndex);
                    }
                } else if ((footIndex = mFooter.indexOfKey(viewType)) >= 0) {
                    if (mListener != null) {
                        return mListener.onCreateViewHolder(parent, makeHeaderFooterFlag(MODE_HEADER, generateFooterIndexWithViewType(viewType)));
                    } else {
                        v = mFooter.valueAt(footIndex);
                    }
                }

                return new ViewHolder(v) {
                    @Override
                    public String toString() {
                        return super.toString();
                    }
                };


            } else {
                return mInternalAdapter.onCreateViewHolder(parent, viewType);
            }
        }

        @Override
        public final void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
            final int adapterPos = getAdapterPosition(position);

            if (adapterPos >= 0) {
                mInternalAdapter.onBindViewHolder(holder, adapterPos, payloads);
            } else if (mListener != null) {
                if (position < mHeader.size()) {
                    mListener.onBindViewHolder(holder, makeHeaderFooterFlag(MODE_HEADER, getHeaderIndexWithParentPosition(position)), holder.itemView);
                } else if (position >= mHeader.size() + mMyItemCount) {
                    mListener.onBindViewHolder(holder, makeHeaderFooterFlag(MODE_FOOTER, generateFooterIndexWithViewType(position)), holder.itemView);
                }
            }

        }

        @Override
        public final void onBindViewHolder(ViewHolder holder, int position) {

        }

        @Override
        public final long getItemId(int position) {
            final int adapterPos = getAdapterPosition(position);

            if (adapterPos >= 0)
                return mInternalAdapter.getItemId(adapterPos);
            return -1;
        }

        /**
         * 根据position计算是第几个adapter的position
         */
        int getAdapterPosition(int positionInParent) {
            int numHeaders = getHeaderCount();
            final int adjPosition = positionInParent - numHeaders;
            final int adapterCount = mMyItemCount;
            if (positionInParent >= numHeaders && adjPosition < adapterCount) {
                return adjPosition;
            }
            return -1;
        }

        /**
         * 根据positionInParent计算HeaderView的索引值
         */
        int getHeaderIndexWithParentPosition(int positionInParent) {
            int headerType = findHeaderViewTypeByPositionInParent(positionInParent);
            if (headerType >= 0)
                return -1;

            return generateHeaderIndexWithViewType(headerType);
        }

        /**
         * 根据positionInParent计算FooterView的索引值
         */
        int getFooterIndexWithParentPosition(int positionInParent) {
            final int footerType = findFooterViewTypeByPositionInParent(positionInParent);
            if (footerType >= 0)
                return -1;
            return generateFooterIndexWithViewType(footerType);
        }

        /**
         * 根据positionInParent计算是第几个HeaderView
         */
        int getHeaderPositionWithParentPosition(int positionInParent) {
            int numHeaders = getHeaderCount();
            return positionInParent < numHeaders ? positionInParent : -1;
        }

        /**
         * 根据positionInParent计算是第几个FooterView
         */
        int getFooterPositionWithParentPosition(int positionInParent) {
            final int items = getItemCount();
            final int numFooters = getFooterCount();
            int numBeforeFooter = items - numFooters;
            final int adjPosition = positionInParent - numBeforeFooter;
            return positionInParent >= numBeforeFooter && adjPosition < numFooters ? adjPosition : -1;
        }

        //        boolean checkInAdapterPositions(int position) {
//            int numHeaders = getHeaderCount();
//            final int adjPosition = position - numHeaders;
//            final int adapterCount = getItemCount2();
//            if (position >= numHeaders && adjPosition < adapterCount) {
//                return true;
//            }
//            return false;
//
//        }


        class InternalAdapterDataObserver extends RecyclerView.AdapterDataObserver {
            @Override
            public void onChanged() {
                ensureInternalAdapterParams();
                notifyDataSetChanged();
//                notifyItemRangeChanged(getHeaderCount(), getInternalAdapterItemCount());
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount) {
                ensureInternalAdapterParams();
                notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount);
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
                ensureInternalAdapterParams();
                notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount, payload);
            }

            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {
                ensureInternalAdapterParams();
                notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount);
            }

            @Override
            public void onItemRangeRemoved(int positionStart, int itemCount) {
                ensureInternalAdapterParams();
                notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount);
            }

            @Override
            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
                ensureInternalAdapterParams();
                final int headerCount = getHeaderCount();
                notifyItemMoved(fromPosition + headerCount, toPosition + headerCount);
            }
        }

        @Override
        public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
            if (mInternalAdapter != null) {
                if (mInternalAdapterDataObserver == null) {
                    mInternalAdapterDataObserver = new InternalAdapterDataObserver();
                    mInternalAdapter.registerAdapterDataObserver(mInternalAdapterDataObserver);
                }
            }
            super.registerAdapterDataObserver(observer);


        }

        @Override
        public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
            super.unregisterAdapterDataObserver(observer);
            if (mInternalAdapter != null && mInternalAdapterDataObserver != null) {
                mInternalAdapter.unregisterAdapterDataObserver(mInternalAdapterDataObserver);
                mInternalAdapterDataObserver = null;
            }
        }


        final int getHeaderCount() {
            return mHeader.size();
        }

        final int getFooterCount() {
            return mFooter.size();
        }

        @Override
        public final int getItemCount() {
            return getHeaderCount() + mMyItemCount + getFooterCount();
        }

        @Override
        public void onViewDetachedFromWindow(ViewHolder holder) {
            final int adapterPos = getAdapterPosition(holder.getAdapterPosition());

            if (adapterPos >= 0 && mInternalAdapter != null) {
                mInternalAdapter.onViewDetachedFromWindow(holder);
            }
        }

        @Override
        public boolean onFailedToRecycleView(ViewHolder holder) {
            final int adapterPos = getAdapterPosition(holder.getAdapterPosition());

            if (adapterPos >= 0 && mInternalAdapter != null) {
                return mInternalAdapter.onFailedToRecycleView(holder);
            }

            return false;
        }

        @Override
        public void onViewRecycled(ViewHolder holder) {
            final int adapterPos = getAdapterPosition(holder.getAdapterPosition());

            if (adapterPos >= 0 && mInternalAdapter != null) {
                mInternalAdapter.onViewRecycled(holder);
            }
        }

        @Override
        public void onViewAttachedToWindow(ViewHolder holder) {
            final int adapterPos = getAdapterPosition(holder.getAdapterPosition());

            if (adapterPos >= 0 && mInternalAdapter != null) {
                mInternalAdapter.onViewAttachedToWindow(holder);
            }
        }

        @Override
        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
            if (mInternalAdapter != null) {
                mInternalAdapter.onDetachedFromRecyclerView(recyclerView);
            }
        }

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            if (mInternalAdapter != null) {
                mInternalAdapter.onAttachedToRecyclerView(recyclerView);
            }
        }

    }


    public abstract static class Adapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
        public int getSpanSize(int position) {
            return getTotalSpanSize();
        }

        public int getTotalSpanSize() {
            return 1;
        }

        public int getExpandStart() {
            return 0;
        }

        public int getExpandCount() {
            return 0;
        }
    }

    public abstract static class BaseHeaderFooterItemDecoration extends RecyclerView.ItemDecoration {


        int getChildPositionInParent(View view) {
            final int posInParent = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
            return posInParent;
        }

        @Override
        public void onDraw(Canvas c, RecyclerView parent, State state) {
            c.save();

            final HeaderFooterRecyclerView recyclerView = (HeaderFooterRecyclerView) parent;
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = parent.getChildAt(i);
                final int posInParent = getChildPositionInParent(child);
                if (posInParent < 0)
                    return;
                int headerIndex = recyclerView.getHeaderIndexWithParentPosition(posInParent);
                if (headerIndex >= 0) {
                    onHeaderDraw(headerIndex, child, c, recyclerView, state);
                    continue;
                }
                int footerIndex = recyclerView.getFooterIndexWithParentPosition(posInParent);
                if (footerIndex >= 0) {
                    onFooterDraw(footerIndex, child, c, recyclerView, state);

                    continue;
                }
                final int adapterPosition = recyclerView.getAdapterPosition(posInParent);
                if (adapterPosition >= 0) {
                    onAdapterItemDraw(adapterPosition, child, c, recyclerView, state);

                }


            }
            c.restore();

        }

        public void onHeaderDraw(int index, View child, Canvas c, HeaderFooterRecyclerView parent, State state) {
        }


        public void onFooterDraw(int index, View child, Canvas c, HeaderFooterRecyclerView parent, State state) {
        }


        public void onAdapterItemDraw(int position, View child, Canvas c, HeaderFooterRecyclerView parent, State state) {
        }


        @Override
        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
            c.save();

            final HeaderFooterRecyclerView recyclerView = (HeaderFooterRecyclerView) parent;
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = parent.getChildAt(i);
                final int posInParent = getChildPositionInParent(child);
                if (posInParent < 0)
                    return;
                int headerIndex = recyclerView.getHeaderIndexWithParentPosition(posInParent);
                if (headerIndex >= 0) {
                    onHeaderDrawOver(headerIndex, child, c, recyclerView, state);
                    continue;
                }
                int footerIndex = recyclerView.getFooterIndexWithParentPosition(posInParent);
                if (footerIndex >= 0) {
                    onFooterDrawOver(footerIndex, child, c, recyclerView, state);
                    continue;
                }
                final int adapterPosition = recyclerView.getAdapterPosition(posInParent);
                if (adapterPosition >= 0) {
                    onAdapterItemDrawOver(adapterPosition, child, c, recyclerView, state);
                }
            }
            c.restore();

        }

        public void onHeaderDrawOver(int index, View child, Canvas c, HeaderFooterRecyclerView parent, State state) {
        }


        public void onFooterDrawOver(int index, View child, Canvas c, HeaderFooterRecyclerView parent, State state) {
        }


        public void onAdapterItemDrawOver(int position, View child, Canvas c, HeaderFooterRecyclerView parent, State state) {
        }


        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
            final HeaderFooterRecyclerView recyclerView = (HeaderFooterRecyclerView) parent;
            final int posInParent = getChildPositionInParent(view);
            if (posInParent < 0)
                return;

            int headerIndex = recyclerView.getHeaderIndexWithParentPosition(posInParent);
            if (headerIndex >= 0) {
                getHeaderOffsets(headerIndex, outRect, view, recyclerView, state);

                return;
            }
            int footerIndex = recyclerView.getFooterIndexWithParentPosition(posInParent);
            if (footerIndex >= 0) {
                getFooterOffsets(footerIndex, outRect, view, recyclerView, state);

                return;
            }
            final int adapterPosition = recyclerView.getAdapterPosition(posInParent);
            if (adapterPosition >= 0) {
                getAdapterItemOffsets(adapterPosition, outRect, view, recyclerView, state);

            }
        }

        public void getAdapterItemOffsets(int position, Rect outRect, View view, HeaderFooterRecyclerView parent, State state) {
        }


        public void getHeaderOffsets(int index, Rect outRect, View view, HeaderFooterRecyclerView parent, State state) {
        }


        public void getFooterOffsets(int index, Rect outRect, View view, HeaderFooterRecyclerView parent, State state) {
        }

    }

    public Adapter getSelfAdapter() {
        return mAdapter == null ? null : mAdapter.mInternalAdapter;
    }


}
